package com.example.app2flow

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import com.elvishew.xlog.XLog
import com.example.app2flow.databinding.ActivityMainBinding
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlin.system.measureTimeMillis
//演示flow
class MainActivity : AppCompatActivity() {
    var activityMainBinding: ActivityMainBinding? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        activityMainBinding = ActivityMainBinding.inflate(LayoutInflater.from(this))
        setContentView(activityMainBinding?.root)
        activityMainBinding?.text1?.text = "要么停止成长，要么不断向前";
    }

    fun onclick(view: View) {
        activityMainBinding?.text1?.text = activityMainBinding?.editTextTextPersonName?.text
//        http://www.kotlincn.net/docs/reference/coroutines/flow.html
        /*11*/
//        lifecycleScope.launch {
//            //流使用 emit 函数 发射 值（必须有emit才 collect到值）。
//            //流使用 collect 函数 收集 值。
//            simple().collect {
//                XLog.e("I'm not blocked $it")
//                activityMainBinding?.text1?.text ="I'm not blocked $it"
//            }
//        }

        /*22 **************************************************************************
        流构建器 使用 .asFlow() 扩展函数，可以将各种集合与序列转换为流。*/
        // 将一个整数区间转化为流
//        lifecycleScope.launch {
//            (1..3).asFlow().collect { value -> XLog.e("$value") }
//        }
        /*22_1**************************************************************************
        流构建器第3种（一共3种） 使用 flowOf() 定义了一个发射固定值集的流*/
//        runBlocking { //onEach过度操作符
//            flowOf("one","two","three").onEach { delay(1000) }.collect {   XLog.e("flowOf $it")  }
//        }

        /*33**************************************************************************
         过渡流操作符 */
//        lifecycleScope.launch { testmap() }

        /*44 **************************************************************************
         转换操作符 最通用的一种称为 transform*/


//        lifecycleScope.launch { testtransform() }

        /*55 ********************************************************************************************************************
         构建和收集在同一个线程
         fllowOnr操作符，用于更改流发射的上下文*/
        // lifecycleScope.launch { testFlowOn().collect { XLog.e("flowOn $it ${Thread.currentThread().name} ") } }


        /*66 ********************************************************************************************************************
          launchIn 替换collect我们可以在单独的协程中启动流的收集*/
/*        runBlocking {
            var job = event()
                .onEach {  //过度操作符(处理每个流)， collect是末端操作符
                    XLog.e("flowOn $it ${Thread.currentThread().name}") }
//                .collect { XLog.e("$it") }
//                .launchIn(CoroutineScope(Dispatchers.IO)) //处理流里面的协和可以指定在哪一个作用域里面
                .launchIn(this) //this主线程
//                .join()
            delay(100)
            job.cancelAndJoin()*/

        /*7 ********************************************************************************************************************
           流的取消*/
        /*   //1
           runBlocking {
               withTimeoutOrNull(2000) {
                   simpleFlow6().collect { XLog.e("flowOn $it") }
               }
           }
           //2
           runBlocking {
               simpleFlow6().collect {
                   if (it >= 2) cancel() //直接调用cancel取消流
               }
           }
           //3流的取消检测
           */

        /*7 ********************************************************************************************************************
          背压：收到与流动方向压力叫背压（就比如，在地铁上人多了，有人在背后推着你走，感到了来看自背后压力）*/
      /*  lifecycleScope.launch {
            var time = measureTimeMillis {
                simpleFlow7()
//                    .buffer()//1.增加缓冲解决背压的效率（相当于加长了管子）
//                    .flowOn(Dispatchers.IO)//2.切换到io线程一次性发送，再接收，自带1的缓冲
//                    .conflate()//3.合并发射， 会处理最新的值（中间的值有可能跳过）
//                    .collectLatest {  }//4.只要最后一个值
                    .collect {
                        delay(300)
                        XLog.e("collect $it  ${Thread.currentThread().name}")
                    }
            }
            XLog.e("一共花费${time}秒")

        }*/

    }

    fun simpleFlow7(): Flow<Int> = flow {
        for (i in 1..3) {
            delay(100) // 假装我们在这里做了一些有用的事情
            emit(i) // 发送下一个值
            XLog.e("emit $i  ${Thread.currentThread().name}")
        }
    }

    fun event(): Flow<Int> =
        (1..3).asFlow().onEach { delay(100) }.flowOn(Dispatchers.Default)

    fun simpleFlow6(): Flow<Int> = flow {
        for (i in 1..3) {
            emit(i) // 发送下一个值
            delay(1000) // 假装我们在这里做了一些有用的事情
            XLog.e("flowOn $i")
        }
    }

    fun testFlowOn(): Flow<Int> = flow { // 流构建器
        XLog.e("flow start ${Thread.currentThread().name}")
        for (i in 1..3) {
            delay(1000) // 假装我们在这里做了一些有用的事情
            emit(i) // 发送下一个值
        }
    }.flowOn(Dispatchers.Default)//默认在io线程·

    fun simple(): Flow<Int> = flow { // 流构建器
        for (i in 1..3) {
            delay(1000) // 假装我们在这里做了一些有用的事情
            emit(i) // 发送下一个值
        }
    }

    private suspend fun testtransform() {
//        比如说，使用 transform 我们可以在执行长时间运行的异步请求之前发射一个字符串并跟踪这个响应：
        (1..20).asFlow() // 一个请求流
            .transform { request ->
                emit("Making request $request")
                emit(performRequest(request))
            }
            .collect { response -> activityMainBinding?.text1?.text = "$response" }
    }

    private suspend fun testmap() {
        (1..10)
            .asFlow() //一个请求流.
            .filter { //过滤
                it % 2 == 0
            }
            .map {  //变换
                performRequest(it)
            }
            .collect { response ->
                activityMainBinding?.text1?.text = "$response"
            }
    }

    suspend fun performRequest(request: Int): String {
        delay(1000) // 模仿长时间运行的异步工作
        return "response $request"
    }

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
        }

    }
}